﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;
using Super_Wall_Breaker.Sources.GameElements.Bricks;
using Microsoft.Xna.Framework;
using Super_Wall_Breaker.Sources.GameElements.Items;
using Super_Wall_Breaker.Sources.GameEngine;
using Super_Wall_Breaker.Sources.TeamElements;
using Super_Wall_Breaker.Sources.TeamElements.Players;
using Microsoft.Xna.Framework.Graphics;
using Super_Wall_Breaker.Sources.Factories;

namespace Super_Wall_Breaker.Sources.GameElements.Balls
{
    /// <summary>
    /// Ball class represents a ball in the game.
    /// </summary>
    public class Ball : MovableSprite
    {

        private TeamIndex _lastTouchedTeam;
        private TeamIndex _teamOwner; //This is the team where the ball respawns.

        private int _maxBallRestartPauseTime = 2000; // in ms
        private int _currentBallRestartPauseTime = 0; // This is the timer shown when a ball respawns

        /// <summary>
        /// Gets or sets the last touched team.
        /// </summary>
        /// <value>
        /// The last touched team.
        /// </value>
        public TeamIndex LastTouchedTeam
        {
            get { return this._lastTouchedTeam; }
            set { this._lastTouchedTeam = value; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Ball"/> class.
        /// </summary>
        /// <param name="position">The position.</param>
        /// <param name="speed">The speed.</param>
        /// <param name="sourceRectangle">The source rectangle.</param>
        /// <param name="teamOwner">The team owner(where the ball respawns).</param>
        public Ball(Vector2 position, Vector2 speed,Rectangle? sourceRectangle, TeamIndex teamOwner)
            : base(position, speed, sourceRectangle)
        {
            this._teamOwner = teamOwner;
            this.Initialize();
        }

        /// <summary>
        /// Initializes the ball.
        /// </summary>
        public void Initialize()
        {
            GlobalConfiguration config = GlobalConfiguration.Configuration;
            Random rand = new Random();

            double xDirection = 2 * rand.NextDouble() - 1;

            if (this._teamOwner == TeamIndex.bottom)
            {
                this.Position = new Vector2(config.BallDefaultPosition.X, config.ScreenHeight - config.BallDefaultPosition.Y);
                this.Speed = new Vector2((float)xDirection * GlobalConfiguration.DEFAULT_BALL_SPEED, GlobalConfiguration.DEFAULT_BALL_SPEED);
            }
            else
            {
                this.Position = new Vector2(config.BallDefaultPosition.X, config.BallDefaultPosition.Y);
                this.Speed = new Vector2((float)xDirection * GlobalConfiguration.DEFAULT_BALL_SPEED, -GlobalConfiguration.DEFAULT_BALL_SPEED);
            }

            this._currentBallRestartPauseTime = this._maxBallRestartPauseTime;
            this.Color = Color.Snow;
        }

        /// <summary>
        /// This function updates the ball position in game. It detects if the ball touch the left or right border or if the ball go out of the game.
        /// </summary>
        /// <param name="gameTime"> The GameTime XNA parameter.</param>
        /// <returns> Returns true if the ball go out by the bottom side, false otherwise. Returns null if the ball doesn't go out.</returns>
        public new bool? Update(GameTime gameTime)
        {
                bool? ballState = null;

                this._currentBallRestartPauseTime -= gameTime.ElapsedGameTime.Milliseconds;

                if (_currentBallRestartPauseTime <= 0)
                {
                    this.Color = TeamsFactory.GetTeamColor(this._teamOwner);
                    GlobalConfiguration config = GlobalConfiguration.Configuration;

                    float nextX = this.Position.X + this.Speed.X * (float)gameTime.ElapsedGameTime.TotalMilliseconds;
                    float nextY = this.Position.Y + this.Speed.Y * (float)gameTime.ElapsedGameTime.TotalMilliseconds;

                    //If the ball hurts right or left side of the window
                    //We redirect the ball with an angle of 90 degrees 
                    if (nextX < 0 || nextX + this.SourceRectangle.Value.Width > config.ScreenWidth)
                    {
                        this.Speed = new Vector2(-this.Speed.X, this.Speed.Y);
                    }
                    else if (nextY + this.SourceRectangle.Value.Height < 0)
                    {
                        ballState = false;
                    }
                    else if (nextY > config.ScreenHeight)
                    {
                        ballState = true;
                    }

                    base.Update(gameTime);
                }

            return ballState;
        }

        /// <summary>
        /// Draws the ball.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch.</param>
        /// <param name="font">The font.</param>
        public void Draw(SpriteBatch spriteBatch, SpriteFont font)
        {
            base.Draw(spriteBatch);

            if(this._currentBallRestartPauseTime > 0)
                spriteBatch.DrawString(font,String.Format("{0}", (float)(this._currentBallRestartPauseTime / 1000.0f)), new Vector2(this.Position.X + this.SourceRectangle.Value.Height, this.Position.Y), this.Color);
        }

        /// <summary>
        /// This function returns true if the ball is respawning and the timer has not reach 0.
        /// </summary>
        /// <returns>Returns true if the ball is respawning and the timer has not reach 0.</returns>
        public bool BallIsWaiting()
        {
            bool returnVal = true;

            if (this._currentBallRestartPauseTime <= 0)
            {
                returnVal = false;
            }

            return returnVal;
        }
    }
}
